﻿using System;
using System.Collections.Generic;
using Newtonsoft.Json;

[JsonObject(IsReference = true)]
[Serializable]
public class DebugData
{
    public GlobalInfo MyGlobalInfo = new GlobalInfo();
    // 所有对象总表
    public Dictionary<string, ObjectInfo> ObjectDic = new Dictionary<string, ObjectInfo>();
    private List<ObjectInfo> _objectInfos = new List<ObjectInfo>();

    public string RegisterAddress;

    // Register下按广度优先
    public ObjectTreeNode BFSTree;
    //    public List<ObjectInfo> FreeTree;//不能由Register遍历到的牛鬼蛇神。

    public void AddObject(string address, ObjectInfo objectInfo)
    {
        ObjectDic[address] = objectInfo;
        _objectInfos.Add(objectInfo);
    }

    public ObjectInfo GetObject(string address)
    {
        if (ObjectDic.ContainsKey(address))
            return ObjectDic[address];
        else
        {
            return null;
        }
    }

    public void AddRelation(string parentAddress, string childAddress, string relationKey)
    {
        ObjectInfo parentObj = GetObject(parentAddress);
        ObjectInfo childObj = GetObject(childAddress);
        if (parentObj != null && childObj != null)
        {
            parentObj.AddChild(relationKey, childObj);
            childObj.AddParent(relationKey, parentObj);
        }
    }

    public void AddUpValueRelation(string parentAddress, string childAddress, string relationKey)
    {
        ObjectInfo parentObj = GetObject(parentAddress);
        ObjectInfo childObj = GetObject(childAddress);
        if (parentObj != null && childObj != null)
        {
            parentObj.AddUpvalue(relationKey, childObj);
            childObj.AddParent(relationKey, parentObj);
        }
    }

    public void Generate()
    {
        int count = _objectInfos.Count;
        // 有一些table是无根的，无法被遍历到。
        // 比如local xx = {}，xx既不是upvalue又不被外部引用

        Queue<ObjectInfo> queue = new Queue<ObjectInfo>();
        queue.Enqueue(BFSTree.MyObjectInfo);
        while (queue.Count != 0)
        {
            ObjectInfo topObject = queue.Dequeue();
            if (topObject.Marked == false)
            {
                topObject.Marked = true;

                ObjectTreeNode childNode = null;
                foreach (var pair in topObject.Childs)
                {
                    childNode = new ObjectTreeNode(pair.Key);
                    childNode.SetInfo(pair.Value, this);
                    childNode.Path = topObject.MyTreeNode.Path + "." + childNode.Desc;
                    childNode.Parent = topObject.MyTreeNode;
                    topObject.MyTreeNode.AddChild(childNode);
                    queue.Enqueue(childNode.MyObjectInfo);
                }
            }
        }
        queue.Clear();
    }
}

[Serializable]
public class GlobalInfo
{
    public int TableCount;
    public double TableSize;
    public int FuncCount;
    public double FuncSize;
    public int StrCount;
    public double StrSize;
    public int ProtoCount;
    public double ProtoSize;
    public int OtherCount;
}

[Serializable]
[JsonObject(IsReference = true)]
public class ObjectInfo
{
    public string Address;
    public int Type;

    public double Size;
    public int Count;

    //key2object
    public Dictionary<string, string> Parents = new Dictionary<string, string>();
    public Dictionary<string, string> Childs = new Dictionary<string, string>();
    public Dictionary<string, string> Upvalues = new Dictionary<string, string>();

    public bool Marked = false;
    public ObjectTreeNode MyTreeNode;

    public virtual void AddChild(string key, ObjectInfo objectInfo)
    {
        Childs[key] = objectInfo.Address;
    }

    public virtual void AddParent(string key, ObjectInfo objectInfo)
    {
        Parents[key] = objectInfo.Address;
    }

    public virtual void AddUpvalue(string key, ObjectInfo objectInfo)
    {

    }
}

[Serializable]
[JsonObject(IsReference = true)]
public class ObjectTreeNode
{
    public ObjectInfo MyObjectInfo;
    public ObjectTreeNode Parent;
    public string Desc;
    public string Path;
    public List<ObjectTreeNode> Childs = new List<ObjectTreeNode>();


    public ObjectTreeNode(string desc)
    {
        Desc = desc;
    }

    public void SetInfo(string address, DebugData debugData)
    {
        MyObjectInfo = debugData.GetObject(address);
        MyObjectInfo.MyTreeNode = this;
    }

    public void AddChild(ObjectTreeNode treeNode)
    {
        Childs.Add(treeNode);
    }
}

[Serializable]
[JsonObject(IsReference = true)]
public class TableInfo : ObjectInfo
{

    public TableInfo(string address, double size, int count)
    {
        Address = address;
        Size = size;
        Count = count;
        Type = 1;
    }


}

[Serializable]
[JsonObject(IsReference = true)]
public class FuncInfo : ObjectInfo
{

    public FuncInfo(string address, double size)
    {
        Address = address;
        Size = size;
        Type = 2;
    }

    public override void AddUpvalue(string key, ObjectInfo objectInfo)
    {
        Upvalues[key] = objectInfo.Address;
    }
}
